package com.starry.module.system.core.dept.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.starry.core.common.constants.CommonError;
import com.starry.core.common.domain.vo.PageVo;
import com.starry.core.common.execption.ServiceException;
import com.starry.core.redis.service.RedisService;
import com.starry.db.core.enums.DBEnableDisableStatusEnum;
import com.starry.db.core.query.LambdaQueryWrapperX;
import com.starry.module.system.api.dept.domain.qo.SysDeptPageQo;
import com.starry.module.system.api.dept.domain.qo.SysDeptQo;
import com.starry.module.system.api.dept.domain.vo.SysDeptDtlVo;
import com.starry.module.system.api.dept.domain.vo.SysDeptTreeVo;
import com.starry.module.system.api.dept.domain.vo.SysDeptVo;
import com.starry.module.system.core.dept.entity.SysDept;
import com.starry.module.system.core.dept.mapper.SysDeptMapper;
import com.starry.module.system.core.dept.service.SysDeptService;
import com.starry.module.system.core.redis.RedisKeyConstants;
import com.starry.module.system.core.user.service.SysUserService;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * 系统机构-服务实现
 *
 * @author xiaoke
 */
@Service("sysDeptService")
public class SysDeptServiceImpl implements SysDeptService {

    private final SysDeptMapper sysDeptMapper;
    private final RedisService redisService;
    private final SysUserService sysUserService;

    @Lazy
    public SysDeptServiceImpl(SysDeptMapper sysDeptMapper, RedisService redisService, SysUserService sysUserService) {
        this.sysDeptMapper = sysDeptMapper;
        this.redisService = redisService;
        this.sysUserService = sysUserService;
    }

    @Override
    public PageVo<SysDeptVo> page(SysDeptPageQo pageQo) {
        PageVo<SysDept> page = sysDeptMapper.selectPage(pageQo);
        List<SysDeptVo> vos = BeanUtil.copyToList(page.getRows(), SysDeptVo.class);
        return new PageVo<>(vos, page.getTotal());
    }

    @Override
    public SysDeptDtlVo getById(Long id) {
        SysDept sysDept = sysDeptMapper.selectById(id);
        if (sysDept == null) {
            throw new ServiceException(CommonError.DATA_NOT_EXISTS.getMsg());
        }
        return BeanUtil.toBean(sysDept, SysDeptDtlVo.class);
    }

    @Override
    public List<SysDeptTreeVo> selectTree(SysDeptPageQo pageQo) {
        List<SysDept> deptList = sysDeptMapper.selectTree(pageQo);
        if (deptList.isEmpty()) {
            return List.of();
        }
        List<SysDeptTreeVo> deptTree = getDeptTree(0L, BeanUtil.copyToList(deptList, SysDeptTreeVo.class));
        redisService.setCacheList(RedisKeyConstants.SYS_DEPT_TREE, deptTree);
        return deptTree;
    }

    @Transactional
    @Override
    public Long save(SysDeptQo sysDeptQo) {
        LambdaQueryWrapperX<SysDept> wrapper = new LambdaQueryWrapperX<>();
        wrapper
                .eq(SysDept::getCode, sysDeptQo.getCode())
                .eq(SysDept::getName, sysDeptQo.getName());
        if (sysDeptMapper.selectCount(wrapper) > 0) {
            throw new ServiceException(CommonError.DATA_EXISTS.getMsg());
        }

        // 校验数据
        validateDept(sysDeptQo);

        SysDept sysDept = BeanUtil.toBean(sysDeptQo, SysDept.class);
        sysDept.setId(null);
        sysDeptMapper.insert(sysDept);
        deleteCache();
        return sysDept.getId();
    }

    @Override
    public boolean existDeptList(Set<Long> deptIdList) {
        if (deptIdList.isEmpty()) return true;
        LambdaQueryWrapperX<SysDept> queryWrapper = new LambdaQueryWrapperX<>();
        queryWrapper.in(SysDept::getId, deptIdList);
        return sysDeptMapper.selectCount(queryWrapper) == deptIdList.size();
    }

    @Override
    public boolean existDeptListStatus(Set<Long> deptIdList) {
        if (deptIdList.isEmpty()) return true;
        LambdaQueryWrapperX<SysDept> queryWrapper = new LambdaQueryWrapperX<>();
        queryWrapper
                .in(SysDept::getId, deptIdList)
                .eq(SysDept::getStatus, DBEnableDisableStatusEnum.ENABLE.getCode());
        return sysDeptMapper.selectCount(queryWrapper) == deptIdList.size();
    }

    @Transactional
    @Override
    public void updateById(SysDeptQo sysDeptQo) {
        if (sysDeptQo.getId() == null) {
            throw new ServiceException(CommonError.DATA_NOT_EXISTS.getMsg());
        }
        LambdaQueryWrapperX<SysDept> wrapper = new LambdaQueryWrapperX<>();
        wrapper
                .ne(SysDept::getId, sysDeptQo.getId())
                .and(w ->
                        w.eq(SysDept::getName, sysDeptQo.getName())
                                .eq(SysDept::getCode, sysDeptQo.getCode())
                );
        if (sysDeptMapper.selectCount(wrapper) > 0) {
            throw new ServiceException(CommonError.DATA_EXISTS.getMsg());
        }

        // 校验数据
        validateDept(sysDeptQo);

        SysDept sysDept = sysDeptMapper.selectById(sysDeptQo.getId());
        if (sysDept == null) {
            throw new ServiceException(CommonError.DATA_NOT_EXISTS.getMsg());
        }
        BeanUtil.copyProperties(sysDeptQo, sysDept);
        sysDeptMapper.updateById(sysDept);
        deleteCache();
    }

    @Transactional
    @Override
    public void removeByIds(Set<Long> idList) {
        if (idList.isEmpty()) return;
        sysDeptMapper.deleteByIds(idList);
    }

    @Transactional
    @Override
    public void enable(Set<Long> idList) {
        if (idList.isEmpty()) return;
        sysDeptMapper.updateBatch(setDeptStatus(idList, DBEnableDisableStatusEnum.ENABLE));
    }

    @Transactional
    @Override
    public void disable(Set<Long> idList) {
        if (idList.isEmpty()) return;
        sysDeptMapper.updateBatch(setDeptStatus(idList, DBEnableDisableStatusEnum.DISABLE));
    }

    @Override
    public List<SysDeptVo> getByUserIdList(Long userId) {
        return sysDeptMapper.selectByUserIDeptList(userId);
    }

    private Set<SysDept> setDeptStatus(Set<Long> idList, DBEnableDisableStatusEnum status) {
        Set<SysDept> sysDepts = new HashSet<>();
        idList.forEach(item -> {
            SysDept sysDept = new SysDept();
            sysDept.setId(item);
            sysDept.setStatus(status.getCode());
            sysDepts.add(sysDept);
        });
        return sysDepts;
    }

    /**
     * 递归获取机构树
     *
     * @param pid   父id
     * @param depts 机构列表
     * @return List<SysDeptTreeVo>
     */
    private List<SysDeptTreeVo> getDeptTree(Long pid, List<SysDeptTreeVo> depts) {
        List<SysDeptTreeVo> children = new ArrayList<>();
        for (SysDeptTreeVo dept : depts) {
            if (dept.getPid().equals(pid)) {
                children.add(dept);
                // 递归调用
                dept.setChildren(getDeptTree(dept.getId(), depts));
            }
        }
        return children.stream()
                .sorted(Comparator.comparingInt(SysDeptTreeVo::getDeptRank))
                .toList();
    }


    /**
     * 校验机构信息
     *
     * @param sysDeptQo 机构信息
     */
    private void validateDept(SysDeptQo sysDeptQo) {
        if (sysDeptQo.getPid() != null) {
            if (sysDeptMapper.selectCount(SysDept::getId, sysDeptQo.getId()) < 0) {
                throw new ServiceException("父级机构不存在");
            }
        }
        if (sysDeptQo.getLeaderUserIds() != null && !sysDeptQo.getLeaderUserIds().isEmpty()) {
            if (!sysUserService.existUserList(sysDeptQo.getLeaderUserIds())) {
                throw new ServiceException("机构负责人不存在");
            }
        }
    }

    /**
     * 删除缓存
     */
    private void deleteCache() {
        redisService.deleteObject(RedisKeyConstants.SYS_DEPT_TREE);
    }
}

